home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / src / ball.c < prev    next >
C/C++ Source or Header  |  1992-11-05  |  16KB  |  582 lines

  1. /*    SCCS Id: @(#)ball.c    3.1    92/11/04    */
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /* Ball & Chain =============================================================*/
  6.  
  7. #include "hack.h"
  8.  
  9. static void NDECL(litter);
  10.  
  11. void
  12. ballfall()
  13. {
  14.     boolean gets_hit;
  15.  
  16.     gets_hit = (((uball->ox != u.ux) || (uball->oy != u.uy)) &&
  17.             ((uwep == uball)? FALSE : (boolean)rn2(5)));
  18.     if (carried(uball)) {
  19.         pline("Startled, you drop the iron ball.");
  20.         if (uwep == uball)
  21.             setuwep((struct obj *)0);
  22.         if (uwep != uball)
  23.             freeinv(uball);
  24.     }
  25.     if(gets_hit){
  26.         int dmg = rn1(7,25);
  27.         pline("The iron ball falls on your %s.",
  28.             body_part(HEAD));
  29.         if (uarmh)
  30.             if(is_metallic(uarmh)) {
  31.             pline("Fortunately, you are wearing a hard helmet.");
  32.             dmg = 3;
  33.             } else if (flags.verbose)
  34.             Your("%s does not protect you.", xname(uarmh));
  35.         losehp(dmg, "Crunched in the head by an iron ball",
  36.             NO_KILLER_PREFIX);
  37.     }
  38. }
  39.  
  40. /*
  41.  *  To make this work, we have to mess with the hero's mind.  The rules for
  42.  *  ball&chain are:
  43.  *
  44.  *    1. If the hero can see them, fine.
  45.  *    2. If the hero can't see either, it isn't seen.
  46.  *    3. If either is felt it is seen.
  47.  *    4. If either is felt and moved, it disappears.
  48.  *
  49.  *  If the hero can see, then when a move is done, the ball and chain are
  50.  *  first picked up, the positions under them are corrected, then they
  51.  *  are moved after the hero moves.  Not too bad
  52.  *
  53.  *  If the hero is blind, then she can "feel" the ball and/or chain at any
  54.  *  time.  However, when the hero moves, the felt ball and/or chain become
  55.  *  unfelt and whatever was felt "under" the ball&chain appears.  Pretty
  56.  *  nifty, but it requires that the ball&chain "remember" what was under
  57.  *  them --- i.e. they pick-up glyphs when they are felt and drop them when
  58.  *  moved (and felt).  When swallowed, the ball&chain are pulled completely
  59.  *  off of the dungeon, but are still on the object chain.  They are placed
  60.  *  under the hero when she is expelled.
  61.  */
  62.  
  63. /*
  64.  *  Place the ball & chain under the hero.  Make sure that the ball & chain
  65.  *  variables are set (actually only needed when blind, but what the heck).
  66.  *  It is assumed that when this is called, the ball and chain are NOT
  67.  *  attached to the object list.
  68.  */
  69. void
  70. placebc()
  71. {
  72.     if (!uchain || !uball) {
  73.     impossible("Where are your ball and chain?");
  74.     return;
  75.     }
  76.  
  77.     uchain->nobj = fobj;        /* put chain on object list */
  78.     fobj = uchain;
  79.  
  80.     if (carried(uball))        /* the ball is carried */
  81.     u.bc_order = 0;            /* chain & ball at different pos */
  82.     else {            /* the ball is NOT carried */
  83.     uball->nobj = fobj;        /* put ball on object list */
  84.     fobj = uball;
  85.  
  86.     place_object(uball, u.ux, u.uy);
  87.     u.bc_order = 1;            /* chain on top */
  88.     }
  89.  
  90.     place_object(uchain, u.ux, u.uy);
  91.  
  92.     u.bglyph = u.cglyph = levl[u.ux][u.uy].glyph;   /* pick up glyph */
  93.  
  94.     newsym(u.ux,u.uy);
  95. }
  96.  
  97. void
  98. unplacebc()
  99. {
  100.     if (u.uswallow) return;    /* ball&chain not placed while swallowed */
  101.  
  102.     if (!carried(uball)) {
  103.     freeobj(uball);
  104.     if (Blind && (u.bc_felt & BC_BALL))        /* drop glyph */
  105.         levl[uball->ox][uball->oy].glyph = u.bglyph;
  106.  
  107.     newsym(uball->ox,uball->oy);
  108.     }
  109.     freeobj(uchain);
  110.     if (Blind && (u.bc_felt & BC_CHAIN))        /* drop glyph */
  111.     levl[uchain->ox][uchain->oy].glyph = u.cglyph;
  112.  
  113.     newsym(uchain->ox,uchain->oy);
  114.     u.bc_felt = 0;                    /* feel nothing */
  115. }
  116.  
  117.  
  118. /*
  119.  *  bc_order()
  120.  *
  121.  *  Return the stacking of the hero's ball & chain.  This assumes that the
  122.  *  hero is being punished.
  123.  *
  124.  *  Return values:
  125.  *    0   ball & chain not at same location
  126.  *    1   chain on top
  127.  *    2   ball on top
  128.  */
  129. int
  130. bc_order()
  131. {
  132.     int order;
  133.     struct obj *obj;
  134.  
  135.     if (uchain->ox != uball->ox || uchain->oy != uball->oy || carried(uball))
  136.     return 0;
  137.  
  138.     obj = level.objects[uchain->ox][uchain->oy];
  139.  
  140.     for (order = -1; obj; obj = obj->nexthere) {
  141.     if (obj == uchain) {
  142.         order = 1;
  143.         break;
  144.     }
  145.     if (obj == uball) {
  146.         order = 2;
  147.         break;
  148.     }
  149.     }
  150.     if (order < 0) {
  151.     impossible("bc_order:  ball&chain not in same location!");
  152.     order = 0;
  153.     }
  154.     return order;
  155. }
  156.  
  157. /*
  158.  *  set_bc()
  159.  *
  160.  *  The hero is either about to go blind or already blind and just punished.
  161.  *  Set up the ball and chain variables so that the ball and chain are "felt".
  162.  */
  163. void
  164. set_bc(already_blind)
  165. int already_blind;
  166. {
  167.     int ball_on_floor = !carried(uball);
  168.     u.bc_order = bc_order();                /* get the order */
  169.     u.bc_felt = ball_on_floor ? BC_BALL|BC_CHAIN : BC_CHAIN;    /* felt */
  170.  
  171.     if (already_blind) {
  172.     u.cglyph = u.bglyph = levl[u.ux][u.uy].glyph;
  173.     return;
  174.     }
  175.  
  176.     /*
  177.      *  Since we can still see, remove the ball&chain and get the glyph that
  178.      *  would be beneath them.  Then put the ball&chain back.  This is pretty
  179.      *  disgusting, but it will work.
  180.      */
  181.     remove_object(uchain);
  182.     if (ball_on_floor) remove_object(uball);
  183.  
  184.     newsym(uchain->ox, uchain->oy);
  185.     u.cglyph = levl[uchain->ox][uchain->oy].glyph;
  186.  
  187.     if (u.bc_order) {            /* same location (ball not carried) */
  188.     u.bglyph = u.cglyph;
  189.     if (u.bc_order == 1) {
  190.         place_object(uball,  uball->ox, uball->oy);
  191.         place_object(uchain, uchain->ox, uchain->oy);
  192.     } else {
  193.         place_object(uchain, uchain->ox, uchain->oy);
  194.         place_object(uball,  uball->ox, uball->oy);
  195.     }
  196.     newsym(uball->ox, uball->oy);
  197.     } else {                    /* different locations */
  198.     place_object(uchain, uchain->ox, uchain->oy);
  199.     newsym(uchain->ox, uchain->oy);
  200.     if (ball_on_floor) {
  201.         newsym(uball->ox, uball->oy);        /* see under ball */
  202.         u.bglyph = levl[uball->ox][uball->oy].glyph;
  203.         place_object(uball,  uball->ox, uball->oy);
  204.         newsym(uball->ox, uball->oy);        /* restore ball */
  205.     }
  206.     }
  207. }
  208.  
  209.  
  210. /*
  211.  *  move_bc()
  212.  *
  213.  *  Move the ball and chain.  This is called twice for every move.  The first
  214.  *  time to pick up the ball and chain before the move, the second time to
  215.  *  place the ball and chain after the move.  If the ball is carried, this
  216.  *  function should never have BC_BALL as part of it's control.
  217.  */
  218. void
  219. move_bc(before, control, ballx, bally, chainx, chainy)
  220. int   before, control;
  221. xchar ballx, bally, chainx, chainy;
  222. {
  223.     if (Blind) {
  224.     /*
  225.      *  The hero is blind.  Time to work hard.  The ball and chain that
  226.      *  are attached to the hero are very special.  The hero knows that
  227.      *  they are attached, so when they move, the hero knows that they
  228.      *  aren't at the last position remembered.  This is complicated
  229.      *  by the fact that the hero can "feel" the surrounding locations
  230.      *  at any time, hence, making one or both of them show up again.
  231.      *  So, we have to keep track of which is felt at any one time and
  232.      *  act accordingly.
  233.      */
  234.     if (!before) {
  235.         if ((control & BC_CHAIN) && (control & BC_BALL)) {
  236.         /*
  237.          *  Both ball and chain moved.  If felt, drop glyph.
  238.          */
  239.         if (u.bc_felt & BC_BALL)            /* ball felt */
  240.             levl[uball->ox][uball->oy].glyph = u.bglyph;
  241.         if (u.bc_felt & BC_CHAIN)            /* chain felt */
  242.             levl[uchain->ox][uchain->oy].glyph = u.cglyph;
  243.         u.bc_felt = 0;
  244.  
  245.         /* Pick up glyph a new location. */
  246.         u.bglyph = levl[ballx][bally].glyph;
  247.         u.cglyph = levl[chainx][chainy].glyph;
  248.  
  249.         movobj(uball,ballx,bally);
  250.         movobj(uchain,chainx,chainy);
  251.         } else if (control & BC_BALL) {
  252.         if (u.bc_felt & BC_BALL) {    /* ball felt */
  253.             if (!u.bc_order) {            /* ball by itself */
  254.             levl[uball->ox][uball->oy].glyph = u.bglyph;
  255.             } else if (u.bc_order == 2) {    /* ball on top */
  256.             if (u.bc_felt & BC_CHAIN) {    /* chain felt */
  257.                 map_object(uchain, 0);
  258.             } else {
  259.                 levl[uball->ox][uball->oy].glyph = u.bglyph;
  260.             }
  261.             }
  262.             u.bc_felt &= ~BC_BALL;    /* no longer feel the ball */
  263.         }
  264.  
  265.         /* Pick up glyph at new position. */
  266.         u.bglyph = (ballx != chainx || bally != chainy) ?
  267.                     levl[ballx][bally].glyph : u.cglyph;
  268.  
  269.         movobj(uball,ballx,bally);
  270.         } else if (control & BC_CHAIN) {
  271.         if (u.bc_felt & BC_CHAIN) {    /* chain felt */
  272.             if (!u.bc_order) {            /* chain by itself */
  273.             levl[uchain->ox][uchain->oy].glyph = u.cglyph;
  274.             } else if (u.bc_order == 1) {   /* chain on top */
  275.             if (u.bc_felt & BC_BALL) {    /* ball felt */
  276.                 map_object(uball, 0);
  277.             } else {
  278.                 levl[uchain->ox][uchain->oy].glyph = u.cglyph;
  279.             }
  280.             }
  281.             u.bc_felt &= ~BC_CHAIN;
  282.         }
  283.         /* Pick up glyph beneath at new position. */
  284.         u.cglyph = (ballx != chainx || bally != chainy) ?
  285.                     levl[chainx][chainy].glyph : u.bglyph;
  286.  
  287.         movobj(uchain,chainx,chainy);
  288.         }
  289.  
  290.         u.bc_order = bc_order();    /* reset the order */
  291.     }
  292.  
  293.     } else {
  294.     /*
  295.      *  The hero is not blind.  To make this work correctly, we need to
  296.      *  pick up the ball and chain before the hero moves, then put them
  297.      *  in their new positions after the hero moves.
  298.      */
  299.     if (before) {
  300.         /*
  301.          *  Neither ball nor chain moved, so remember which was on top.
  302.          *  Use the variable 'u.bc_order' since it is only valid when
  303.          *  blind.
  304.          */
  305.         if (!control) u.bc_order = bc_order();
  306.  
  307.         remove_object(uchain);
  308.         newsym(uchain->ox, uchain->oy);
  309.         if (!carried(uball)) {
  310.         remove_object(uball);
  311.         newsym(uball->ox,  uball->oy);
  312.         }
  313.     } else {
  314.         int on_floor = !carried(uball);
  315.  
  316.         if ((control & BC_CHAIN) || (!control && u.bc_order == 1)) {
  317.         /* If the chain moved or nothing moved & chain on top. */
  318.         if (on_floor) place_object(uball,  ballx, bally);
  319.         place_object(uchain, chainx, chainy);    /* chain on top */
  320.         } else {
  321.         place_object(uchain, chainx, chainy);
  322.         if (on_floor) place_object(uball,  ballx, bally);
  323.                                 /* ball on top */
  324.         }
  325.         newsym(chainx, chainy);
  326.         if (on_floor) newsym(ballx, bally);
  327.     }
  328.     }
  329. }
  330.  
  331. /* return TRUE if ball could be dragged */
  332. boolean
  333. drag_ball(x, y, bc_control, ballx, bally, chainx, chainy)
  334. xchar x, y;
  335. int *bc_control;
  336. xchar *ballx, *bally, *chainx, *chainy;
  337. {
  338.     struct trap *t = (struct trap *)0;
  339.  
  340.     *ballx  = uball->ox;
  341.     *bally  = uball->oy;
  342.     *chainx = uchain->ox;
  343.     *chainy = uchain->oy;
  344.     *bc_control = 0;
  345.  
  346.     if (dist2(x, y, uchain->ox, uchain->oy) <= 2) {
  347.         *bc_control = 0;    /* nothing moved */
  348.         move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
  349.         return TRUE;
  350.     }
  351.  
  352.     if (carried(uball) || dist2(x, y, uball->ox, uball->oy) < 3 ||
  353.         (uball->ox == uchain->ox && uball->oy == uchain->oy)) {
  354.         *chainx = u.ux;
  355.         *chainy = u.uy;
  356.         *bc_control = BC_CHAIN;
  357.         move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
  358.         return TRUE;
  359.     }
  360.  
  361.     if (near_capacity() > SLT_ENCUMBER) {
  362.         You("cannot %sdrag the heavy iron ball.",
  363.                 invent ? "carry all that and also " : "");
  364.         nomul(0);
  365.         return FALSE;
  366.     }
  367.  
  368.     if ((is_pool(uchain->ox, uchain->oy) &&
  369.             (levl[uchain->ox][uchain->oy].typ == POOL ||
  370.              !is_pool(uball->ox, uball->oy) || 
  371.              levl[uball->ox][uball->oy].typ == POOL))
  372.         || ((t = t_at(uchain->ox, uchain->oy)) && 
  373.             (t->ttyp == PIT ||
  374.              t->ttyp == SPIKED_PIT ||
  375.              t->ttyp == TRAPDOOR)) ) {
  376.  
  377.         if (Levitation) {
  378.         You("feel a tug from your iron ball.");
  379.         if (t) t->tseen = 1;
  380.         } else {
  381.         struct monst *victim;
  382.  
  383.         You("are jerked back by your iron ball!");
  384.         if (victim = m_at(uchain->ox, uchain->oy)) {
  385.             int tmp;
  386.  
  387.             tmp = -2 + Luck + find_mac(victim);
  388.  
  389.             if (victim->msleep) {
  390.             victim->msleep = 0;
  391.             tmp += 2;
  392.             }
  393.             if (!victim->mcanmove) {
  394.             tmp += 4;
  395.             if (!rn2(10)) {
  396.                 victim->mcanmove = 1;
  397.                 victim->mfrozen = 0;
  398.             }
  399.             }
  400.             if (tmp >= rnd(20))
  401.             (void) hmon(victim,uball,1); 
  402.             else 
  403.             miss(xname(uball), victim);
  404.  
  405.         }         /* now check again in case mon died */
  406.         if (!m_at(uchain->ox, uchain->oy)) {
  407.             u.ux = uchain->ox;
  408.             u.uy = uchain->oy;
  409.             newsym(u.ux0, u.uy0);
  410.         }
  411.         nomul(0);
  412.  
  413.         *ballx = uchain->ox;
  414.         *bally = uchain->oy;
  415.         *bc_control = BC_BALL;
  416.         move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
  417.         move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy);
  418.         spoteffects();
  419.         return FALSE;
  420.         } 
  421.     }
  422.  
  423.     *ballx  = uchain->ox;
  424.     *bally  = uchain->oy;
  425.     *chainx = u.ux;
  426.     *chainy = u.uy;
  427.     *bc_control = BC_BALL|BC_CHAIN;;
  428.     nomul(-2);
  429.     nomovemsg = "";
  430.  
  431.     move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
  432.     return TRUE;
  433. }
  434.  
  435. /*
  436.  *  drop_ball()
  437.  *
  438.  *  The punished hero drops or throws her iron ball.  If the hero is
  439.  *  blind, we must reset the order and glyph.  Check for side effects.
  440.  *  This routine expects the ball to be already placed.
  441.  */
  442. void
  443. drop_ball(x, y)
  444. xchar x, y;
  445. {
  446.     if (Blind) {
  447.     u.bc_order = bc_order();            /* get the order */
  448.                             /* pick up glyph */
  449.     u.bglyph = (u.bc_order) ? u.cglyph : levl[x][y].glyph;
  450.     }
  451.  
  452.     if (x != u.ux || y != u.uy) {
  453.     struct trap *t;
  454.     const char *pullmsg = "The ball pulls you out of the %s!";
  455.  
  456.     if (u.utrap && u.utraptype != TT_INFLOOR) {
  457.         switch(u.utraptype) {
  458.         case TT_PIT:
  459.         pline(pullmsg, "pit");
  460.         break;
  461.         case TT_WEB:
  462.         pline(pullmsg, "web");
  463.         pline("The web is destroyed!");
  464.         deltrap(t_at(u.ux,u.uy));
  465.         break;
  466.         case TT_LAVA:
  467.         pline(pullmsg, "lava");
  468.         break;
  469.         case TT_BEARTRAP: {
  470.         register long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
  471.         pline(pullmsg, "bear trap");
  472.         Your("%s %s is severely damaged.",
  473.                     (side == LEFT_SIDE) ? "left" : "right",
  474.                     body_part(LEG));
  475.         set_wounded_legs(side, rn1(1000, 500));
  476.         losehp(2, "leg damage from being pulled out of a bear trap",
  477.                     KILLED_BY);
  478.         break;
  479.           }
  480.         }
  481.         u.utrap = 0;
  482.         fill_pit(u.ux, u.uy);
  483.     }
  484.  
  485.     u.ux0 = u.ux;
  486.     u.uy0 = u.uy;
  487.     if (!Levitation && !MON_AT(x, y) && !u.utrap &&
  488.                 (is_pool(x, y) ||
  489.                  ((t = t_at(x, y)) &&
  490.                   ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT) ||
  491.                    (t->ttyp == TRAPDOOR))))) {
  492.         u.ux = x;
  493.         u.uy = y;
  494.     } else {
  495.         u.ux = x - u.dx;
  496.         u.uy = y - u.dy;
  497.     }
  498.     vision_full_recalc = 1;    /* hero has moved, recalculate vision later */
  499.  
  500.     if (Blind) {
  501.         /* drop glyph under the chain */
  502.         if (u.bc_felt & BC_CHAIN)
  503.         levl[uchain->ox][uchain->oy].glyph = u.cglyph;
  504.         u.bc_felt  = 0;        /* feel nothing */
  505.         u.bc_order = bc_order();    /* reset bc order */
  506.     }
  507.     movobj(uchain,u.ux,u.uy);    /* has a newsym */
  508.     newsym(u.ux0,u.uy0);        /* clean up old position */
  509.     spoteffects();
  510.     }
  511. }
  512.  
  513.  
  514. static void
  515. litter()
  516. {
  517.     struct obj *otmp = invent, *nextobj;
  518.     int capacity = weight_cap();
  519.  
  520.     while (otmp) {
  521.         nextobj = otmp->nobj;
  522.         if ((otmp != uball) && (rnd(capacity) <= otmp->owt)) {
  523.             if (otmp == uwep)
  524.                 setuwep((struct obj *)0);
  525.             if ((otmp != uwep) && (canletgo(otmp, ""))) {
  526.                 Your("%s you down the stairs.",
  527.                      aobjnam(otmp, "follow"));
  528.                 dropx(otmp);
  529.             }
  530.         }
  531.         otmp = nextobj;
  532.     }
  533. }
  534.  
  535. void
  536. drag_down()
  537. {
  538.     boolean forward;
  539.     uchar dragchance = 3;
  540.  
  541.     /* 
  542.      *    Assume that the ball falls forward if:
  543.      *
  544.      *    a) the character is wielding it, or
  545.      *    b) the character has both hands available to hold it (i.e. is 
  546.      *       not wielding any weapon), or 
  547.      *    c) (perhaps) it falls forward out of his non-weapon hand
  548.      */
  549.  
  550.     forward = (!(carried(uball))? 
  551.           FALSE : ((uwep == uball) || (!uwep))? 
  552.               TRUE : (boolean)(rn2(3) / 2));
  553.  
  554.     if (carried(uball)) 
  555.         You("lose your grip on the iron ball.");
  556.  
  557.     if (forward) {
  558.         if(rn2(6)) {
  559.             You("get dragged downstairs by the iron ball.");
  560.             losehp(rnd(6), "dragged downstairs by an iron ball",
  561.                 NO_KILLER_PREFIX);
  562.             litter();
  563.         }
  564.     } else {
  565.         if(rn2(2)) {
  566.             pline("The iron ball smacks into you!");
  567.             losehp(rnd(20), "iron ball collision", KILLED_BY_AN);
  568.             exercise(A_STR, FALSE);
  569.             dragchance -= 2;
  570.         } 
  571.         if( (int) dragchance >= rnd(6)) {
  572.             You("get dragged downstairs by the iron ball.");
  573.             losehp(rnd(3), "dragged downstairs by an iron ball",
  574.                 NO_KILLER_PREFIX);
  575.             exercise(A_STR, FALSE);
  576.             litter();
  577.         }
  578.     }
  579. }
  580.  
  581. /*ball.c*/
  582.